/****************************************************************
** Product  :   HP Subscriber Network Application Policy
** Module   :   gr-manager
** Date: Apr 10, 2015               
** Author: Joey Yi
** (C) Copyright 2015, Hewlett-Packard Company, All Rights Reserved.
** This software is the proprietary information of HP, Inc.  
** Use is subject to license terms.
*****************************************************************
** Description:   
**  GRM configuration information management, Loading configuration file into some map objects.
****************************************************************/
package com.hp.snap.gr.utils;

import com.hp.snap.gr.exception.GRMException;
import com.hp.snap.gr.model.Deployment;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.*;

/**
 *GRM configuration information management, Loading configuration file into some map objects.
 *
 * <P>
 * Version: FIXME: 1.0.1 <BR>
 * Author: FIXME: Joey Yi
 * Date: Apr 10, 2015
 * 
 * </P>
 *
 **/
public class GRMConfigManager {

    public static final String GR_GLOBAL_CONFIG_FILE = "GR-Global.config";
    public static final String GR_CONFIG_FILE = "GR.config";
    private static final String GRM_LOCAL_CONFIG_FILE = "grm.properties";
    private static Logger logger = LoggerFactory.getLogger(GRMConfigManager.class);
    private static Map<String, String> grLocalConfig = new HashMap<String, String>();
    private static Map<String, String> grGlobalConfig = new LinkedHashMap<String, String>();
    private static Map<String, String> eiumConfig = new HashMap<String, String>();
    private static Map<String, Object> grGlobalConfigContext = new LinkedHashMap<String, Object>();

    private static Boolean isSecure;
    private static String eIUMVarHome;
    private static Map<String, Deployment> localDeployments = null;
    private static Map<String, Deployment> remoteDeployments = null;
    private static Map<String, String> config = new HashMap<String, String>();

    /**
     * 
     * Password decryption
     *
     * @param secret   password string
     * @return   plaintext password
     */
    public static String decode(String secret) {
        try {
            if (StringUtils.isEmpty(secret) || !secret.startsWith("encrypt://")) {
                return secret;
            }
            secret = secret.replace("encrypt://", "");

            byte[] kbytes = "jaas is the way".getBytes();
            SecretKeySpec key = new SecretKeySpec(kbytes, "Blowfish");
            BigInteger n = new BigInteger(secret, 16);
            byte[] encoding = n.toByteArray();
            Cipher cipher = Cipher.getInstance("Blowfish");
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] decode = cipher.doFinal(encoding);
            return new String(decode);
        } catch (Exception e) {
            logger.error("Password decode failed!"+e.toString());
        }
        return "";
    }

    /**
     * 
     * Check if the eIUM is secure mode.
     *
     * @return
     */
    public static boolean isSecure() {
    	logger.trace("The EIUMVarHome is {}", getEIUMVarHome());
        if (isSecure == null) {
            isSecure = new File(getEIUMVarHome(), "security").isFile();
        }
        logger.trace("isSecure value is {}", isSecure);
        if(!isSecure){
        	grLocalConfig.put("EIUM_USER", "");
        	grLocalConfig.put("EIUM_PWD", "");
        	grLocalConfig.put("DUMP_EIUM_USER", "");
        	grLocalConfig.put("DUMP_EIUM_PWD", "");
        	grLocalConfig.put("SS_CONF_EIUM_USER", "");
        	grLocalConfig.put("SS_CONF_EIUM_PWD", "");
        }else{
        	String eium_user = grLocalConfig.get("EIUM_USER");
        	String eium_pwd = grLocalConfig.get("EIUM_PWD");
        	grLocalConfig.put("DUMP_EIUM_USER", " -U "+eium_user);
        	grLocalConfig.put("DUMP_EIUM_PWD", " -P "+eium_pwd);
        	grLocalConfig.put("SS_CONF_EIUM_USER", " -login "+eium_user);
        	grLocalConfig.put("SS_CONF_EIUM_PWD", " -pw "+eium_pwd);
        }
        return isSecure;
    }

    /**
     * 
     * loading the grm.properties file as local configuration information into grLocalConfig map object.
     *
     * @throws GRMException
     */
    public static void initGRLocalConfig(Map<String, String> config) throws GRMException {
        if (null != config) {
            GRMConfigManager.config = config;
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Starting to read GR local config...");
        }

        if (!grLocalConfig.isEmpty()) {
            if (logger.isDebugEnabled()) {
                logger.debug("GRLocalConfig has been alreday initialized.");
            }
            return;
        }

        InputStream is = null;
        InputStream isIUMInstall = null;
        InputStream isETC = null;
        try {

            // read gr tool local config
            Properties prop = new Properties();
            String localConfigFile = Constants.USER_GR_CONF + File.separator + GRM_LOCAL_CONFIG_FILE;

            File file = new File(localConfigFile);
            if (file.exists()) {
                is = new FileInputStream(file);
            } else {
                is = ClassLoader.getSystemResourceAsStream(GRM_LOCAL_CONFIG_FILE);
            }

            prop.load(is);

            Set<String> propKeys = prop.stringPropertyNames();

            for (String propKey : propKeys) {
                grLocalConfig.put(propKey, decode(prop.getProperty(propKey).trim()));
            }

            grLocalConfig.put("USER_DIR", Constants.USER_DIR);
            grLocalConfig.put("PARAM", config==null?"":config.get(Constants.GET_SESSIONSERVER_CONFIG_PARAM));
            grLocalConfig.put("USER_GR_WORK", Constants.USER_GR_WORK);
            grLocalConfig.put("USER_GR_TEMP", Constants.USER_GR_TEMP);
            grLocalConfig.put("USER_GR_BIN", Constants.USER_GR_BIN);
            grLocalConfig.put("USER_GR_ARTIFACT", Constants.USER_GR_ARTIFACT);

            String siteName = grLocalConfig.get(Constants.CFG_GRL_DEPLOY_NAME);
            String eIUMHome = grLocalConfig.get(Constants.CFG_GRL_eIUM_HOME);

            if (StringUtils.isEmpty(siteName)) {
                throw new GRMException("The site name must be configured, and MASTER-SLAVE relationship also need config in GR global.");
            }

            if (StringUtils.isEmpty(eIUMHome)) {
                throw new GRMException("The eIUMHome must be configured in GR local.");
            }

            // read eIUM local config
            if (logger.isTraceEnabled()) {
                logger.trace("Reading eIUM local config...");
            }

            String eIUMInstall = eIUMHome + File.separator + "siu_install.ini";

            if (!new File(eIUMInstall).exists()) {
                logger.error("Cannot find the eIUM install ini: {}", eIUMInstall);
            }

            isIUMInstall = new FileInputStream(eIUMInstall);
            prop = new Properties();
            prop.load(isIUMInstall);

            eIUMVarHome = prop.getProperty("VarRoot");
            String eIUMEtcHome = prop.getProperty("ConfigRoot");

            if (logger.isTraceEnabled()) {
                logger.trace("eIUM VAR Home: {}", eIUMVarHome);
                logger.trace("eIUM ETC Home: {}", eIUMEtcHome);
            }

            String eIUMEtcConfig = eIUMEtcHome + File.separator + "SIU.ini";
            
            isETC = new FileInputStream(eIUMEtcConfig);

            prop = new Properties();
            prop.load(isETC);
            for (Object key : prop.keySet()) {
                logger.trace("etc key is{}. value is {}", new Object[]{String.valueOf(key), prop.getProperty((String) key)});
                eiumConfig.put(String.valueOf(key), prop.getProperty((String) key));
                
            }

        } catch (GRMException e) {
            throw e;
        } catch (Exception e) {
            throw new GRMException("Load GR local configuration error", e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    //
                }
            }

            if (isIUMInstall != null) {
                try {
                    isIUMInstall.close();
                } catch (IOException e) {
                    //
                }
            }

            if (isETC != null) {
                try {
                    isETC.close();
                } catch (IOException e) {
                    //
                }
            }
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Successful to read GR local config.");
        }
    }

    public static Map<String, String> getGrLocalConfig() {
        return grLocalConfig;
    }

    public static Map<String, String> getGrGlobalConfig() {
        return grGlobalConfig;
    }

    public static Map<String, String> getEiumConfig() {
        return eiumConfig;
    }

    public static String getLocalConfigValue(String localConfigKey) {
        return grLocalConfig.get(localConfigKey);
    }

    public static String getLocalConfigValue(String localConfigKey, String defaultValue) {
        String value = grLocalConfig.get(localConfigKey);
        if (StringUtils.isEmpty(value)) {
            return defaultValue;
        }
        return value;
    }

    public static String getEIUMHome() {
        return getLocalConfigValue(Constants.CFG_GRL_eIUM_HOME);
    }

    public static String getEIUMVarHome() {
        return eIUMVarHome;
    }

    public static String getGRGlobalConfigPath() {
        return Constants.USER_GR_TEMP + File.separator + GR_GLOBAL_CONFIG_FILE;
    }

    public static String getGRConfigPath() {
        return Constants.USER_GR_TEMP + File.separator + GR_CONFIG_FILE;
    }

    public static String getUsername() {
        return getLocalConfigValue(Constants.CFG_GRL_eIUM_USER);
    }

    public static String getPassword() {
        String password = getLocalConfigValue(Constants.CFG_GRL_eIUM_PWD);
        return decode(password);
    }

    public static String getSiteName() {
        return getLocalConfigValue(Constants.CFG_GRL_DEPLOY_NAME);
    }

    /**
     * 
     * initial GR global configuration file GR-Global.config
     *
     * @throws GRMException
     */
    public static void initGRGlobalConfig() throws GRMException {
        if (logger.isDebugEnabled()) {
            logger.debug("Start to read global config...");
        }

        SSConfigUtils.readGlobalConfig(getGRGlobalConfigPath(), grGlobalConfig);

        grGlobalConfigContext = SSConfigUtils.convertToScriptContext(grGlobalConfig);

        if (logger.isDebugEnabled()) {
            logger.debug("Finished to read global config.");
        }
    }

    public static Map<String, Object> getActionPlanInputContext() {
        Map<String, Object> context = new HashMap<String, Object>();
        context.put(Constants.CFG_GR_LOCAL, grLocalConfig);
        context.put(Constants.CFG_GR_GLOBAL, grGlobalConfigContext);

        return context;
    }

    public static Map<String, Object> getContext(Map<String, Object> actionPlanInputs, Map<String, Object> actionPlanOutputs) {
        Map<String, Object> context = new HashMap<String, Object>();
        context.put(Constants.CFG_GR_LOCAL, grLocalConfig);
        context.put(Constants.CFG_GR_GLOBAL, grGlobalConfigContext);

        context.put(Constants.ACTION_INPUT_PARAM, actionPlanInputs);
        context.put(Constants.ACTION_OUTPUT_PARAM, actionPlanOutputs);

        return context;
    }

    /**
     * 
     * Initial local VoltDB deployment information into localDeployments map object.
     *
     * @return
     */
    public static Map<String, Deployment> initLocalDeployment() {
        if (getLocalDeployments() == null) {
            try {
                localDeployments = RESTfulUtils.getVoltDBDeployments(getSiteName());
            } catch (Exception e) {
                Constants.CONSOLE.info("Cannot access VEM to get local deployment info!");
                logger.warn("Cannot get local voltDB deployment information! [" + e.getMessage() + "]");
            }
        }

        return localDeployments;
    }

    /**
     * 
     * Initial remote VoltDB deployment information into remoteDeployments map object.
     *
     * @return
     */
    public static Map<String, Deployment> initRemoteDeployment() {
        if (getRemoteDeployments() == null) {
            try {
                remoteDeployments = RESTfulUtils.getVoltDBDeployments(Utils.getCorrespondSiteName(getSiteName()));
            } catch (Exception e) {
                logger.warn("Cannot get remote voltDB deployment information! [" + e.getMessage() + "]");
            }
        }

        return remoteDeployments;
    }

    public static Map<String, Deployment> getLocalDeployments() {
        return localDeployments;
    }

    public static void setLocalDeployments(Map<String, Deployment> localDeployments) {
        GRMConfigManager.localDeployments = localDeployments;
    }

    public static Map<String, Deployment> getRemoteDeployments() {
        return remoteDeployments;
    }

    public static void setRemoteDeployments(Map<String, Deployment> remoteDeployments) {
        GRMConfigManager.remoteDeployments = remoteDeployments;
    }

    public static Map<String, String> getConfig() {
        return config;
    }

    public static void setConfig(Map<String, String> config) {
        GRMConfigManager.config = config;
    }
}
